#include <iostream>
#include <sstream>
#include <list>
#include <vector>
#include <iomanip>
#include <cmath>
#include <string>
#include <algorithm>

std::string getStddev(const std::list<double> &data, double avg);
std::string getMax5(const std::list<double> &data);
std::string getMin5(const std::list<double> &data);
std::string getSamples(const std::list<double> &data);

int main()
{
    double sum(0);
    std::list<double> data;
    std::srand((uint32_t)time(nullptr));

    while (true)
    {
        // 获取输入
        double number(0);
        std::cout << "> ";
        std::cin >> number;

        // 求和
        sum += number;

        // 排序
        data.push_back(number);
        data.sort();

        double avg = sum / data.size();            // 平均值
        std::string stddev = getStddev(data, avg); // 样本标准差
        std::string max5 = getMax5(data);          // 最大的5个数
        std::string min5 = getMin5(data);          // 最小的5个数
        std::string samples = getSamples(data);    // 随机采样3个

        // 输出结果
        std::cout << std::fixed << std::setprecision(2);
        std::cout << "avg:" << avg << '\t'
                  << "stddev:" << stddev << '\t'
                  << "max5:" << max5 << '\t'
                  << "min5:" << min5 << '\t'
                  << "sample:" << samples << std::endl;
    }

    return 0;
}

std::string getStddev(const std::list<double> &data, double avg)
{
    if (data.size() < 2)
        return "null";

    double sum(0);
    for (auto iter = data.begin(); iter != data.end(); ++iter)
    {
        sum += std::pow(*iter - avg, 2);
    }

    std::ostringstream sstream;
    sstream << std::fixed << std::setprecision(2) << std::sqrt(sum / (data.size() - 1));
    return sstream.str();
}

std::string joinString(const std::vector<std::string> strings)
{
    std::string str;
    str.append("(");
    for (int i=0; i<strings.size(); ++i)
    {
        str.append(strings[i]);
        if (i != strings.size() - 1)
            str.append(",");
    }
    str.append(")");
    return str;
}

std::string getMax5(const std::list<double> &data)
{
    int count = std::min((int)data.size(), 5);

    std::vector<std::string> max5;
    auto iter = data.end();
    for (int i=0; i<count; ++i)
    {
        double num = *(--iter);
        std::ostringstream sstream;
        sstream << std::fixed << std::setprecision(2) << num;
        max5.push_back(sstream.str());
    }

    int nullCount = 5 - (int)max5.size();
    for (int i=0; i<nullCount; ++i)
    {
        max5.push_back("null");
    }

    return joinString(max5);
}

std::string getMin5(const std::list<double> &data)
{
    int count = std::min((int)data.size(), 5);

    std::vector<std::string> min5;
    auto iter = data.begin();
    for (int i=0; i<count; ++i)
    {
        double num = *(iter++);
        std::ostringstream sstream;
        sstream << std::fixed << std::setprecision(2) << num;
        min5.push_back(sstream.str());
    }

    int nullCount = 5 - (int)min5.size();
    for (int i=0; i<nullCount; ++i)
    {
        min5.push_back("null");
    }

    return joinString(min5);
}

std::string getSamples(const std::list<double> &data)
{
    std::vector<std::string> samples;
    std::vector<double> dataCopy;
    dataCopy.assign(data.begin(), data.end());

    int count = std::min((int)dataCopy.size(), 3);

    for (int i=0; i<count; ++i)
    {
        int index = std::rand() % (dataCopy.size());

        std::ostringstream sstream;
        sstream << std::fixed << std::setprecision(2) << dataCopy[index];
        samples.push_back(sstream.str());

        dataCopy.erase(dataCopy.begin() + index);
    }

    int nullCount = 3 - (int)samples.size();
    for (int i=0; i<nullCount; ++i)
    {
        samples.push_back("null");
    }

    return joinString(samples);
}
